import { ref } from "vue";

/**
 * 维护请求状态
 * 如果使用串行需要注意参数问题，参数不同，得先自动重置状态，强制执行
 * @param {Objcect} param0 request 请求， runNow: 立即执行，isSerial： 串行
 * @returns
 */
export function useRequest({
  request,
  runNow = true,
  isSerial,
  initResult,
  isCatch = true,
} = {}) {
  const loading = ref(false);
  const inited = ref(false);
  const isError = ref(false);
  const errorMsg = ref("");
  const result = ref(initResult);
  const isSuccess = ref(false);
  let version = 0;

  const checkAbort = () => {
    if (isSerial && loading.value) {
      return true;
    }
  };

  const doRequest = async (...args) => {
    if (checkAbort()) {
      return false;
    }

    loading.value = true;
    isError.value = false;
    isSuccess.value = false;
    const theVersion = ++version;

    try {
      const res = await request(...args);
      inited.value = true;
      if (theVersion === version) {
        result.value = res;
        errorMsg.value = "";
        isSuccess.value = true;
        loading.value = false;
      }
    } catch (e) {
      if (theVersion === version) {
        isError.value = true;
        result.value = null;
        errorMsg.value = e?.msg || "服务异常";
        loading.value = false;
      }
      if (isCatch) {
        console.error(e);
      } else {
        throw e;
      }
    }

    return result.value;
  };

  // 会强制执行，即使设定了串行
  const forceRequest = async (...args) => {
    loading.value = false;
    isError.value = false;
    isSuccess.value = false;

    return doRequest(...args);
  };

  if (runNow) {
    doRequest();
  }

  return {
    loading,
    isError,
    errorMsg,
    result,
    isSuccess,
    inited,
    doRequest,
    forceRequest,
  };
}

export async function doCatch(request) {
  try {
    await request();
  } catch (e) {
    console.error(e);
  }
}

/**
 * 一次只发起一次请求
 * @param {function} request
 * @returns
 */
export function serialRequest(request) {
  let promise = null;

  return (...args) => {
    if (!promise) {
      promise = request(...args);

      if (promise.finally) {
        promise.finally(() => {
          promise = null;
        });
      }
    }
    return promise;
  };
}
